package com.globallogic.training.basics;

import java.util.*;

public class CalendarSeeker {

	private static final char DATE_SEPARATOR = '/';
	
	private static final int LEAP_YEAR_CYCLE = 4;
	private static final int HUNDRED_YEAR_CYCLE = 100;
	private static final int FOUR_HUNDREDS_YEAR_CYCLE = 400;
			
	private static final String WRONG_DATE = "Wrong date";
	private static final String WRONG_DATE_FORMAT = "Wrong format of date";

	private static boolean checkDate(int day, int month, int year) {
		if (month > 12) {
			return false;
		} 
			
		if (month == 2) {
			if (isLeapYear(year)) {
				if (day <= 29) {
					return true;
				} else {
				return false;
				}
			} else {
				if (day <= 28) {
					return true;
				} else {
					return false;
				}
			}
		} 
		
		if (day < 31) {
			return true;
		} 
		
		if (day > 31) {
			return false;
		}
		
		if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10) {
			return true;
		}
		
		return false;
	}

	private static String getDayOfWeek(int day, int month, int year)
	{
		final int[] monthNumbers = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
		final int leapYearCycle = 4;
		final int hundredYearCycle = 100;
		final int fourHundredsYearCycle = 400;
		final int numberOfDaysInWeek = 7;
	   
		year -=  month < 3 ? 1 : 0;
	   
		switch ((year + year/leapYearCycle - year/hundredYearCycle + year/fourHundredsYearCycle 
			+ monthNumbers[month-1] + day) % numberOfDaysInWeek) {
			case 0:
				return "Sunday";
				
			case 1:
				return "Monday";
				
			case 2:
				return "Tuesday";
				
			case 3:
				return "Wednesday";
				
			case 4:
				return "Thursday";
				
			case 5:
				return "Friday";
				
			default:
				return "Suturday";
		}
	}
	
	private static boolean isLeapYear(int year) {   
		if (year % FOUR_HUNDREDS_YEAR_CYCLE == 0) {
			return true;
		} else if (year % HUNDRED_YEAR_CYCLE == 0) {
			return false;
		} else if (year % LEAP_YEAR_CYCLE == 0) {
			return true;
		} else {
			return false;
		}
	}
	
	private static boolean isExitCode(char[] userCharacters) {
		boolean gotCharQ = false;
		
		for (char userCharacter : userCharacters) {	
			if ((userCharacter == 'q' || userCharacter == 'Q') && !gotCharQ) {
				gotCharQ = true;
			} else if (userCharacter == ' ') {
				continue;
			} else {
				return false;
			}
		}
		
		if (gotCharQ) {
			return true;
		}
		
		return false;
	}
	
	private static boolean checkDateFormat(char[] userCharacters) {
		int dateNumberCounter = 0;
		int dateSeparatorCounter = 0;
		boolean gotSpace = false;
		
		for (char userCharacter : userCharacters) {	
			if (dateSeparatorCounter > 2) {
				return false;
			}

			if (userCharacter >= '0' && userCharacter <= '9' && !(gotSpace && dateNumberCounter > 2)) {
				dateNumberCounter = dateSeparatorCounter + 1;
				gotSpace = false;
			} else if (userCharacter == DATE_SEPARATOR && dateNumberCounter > 0 &&
				!(gotSpace && dateNumberCounter > 2)) {
				dateSeparatorCounter++;
			} else if (userCharacter == ' ' && (dateNumberCounter == 3 || dateNumberCounter == 0)) {
				gotSpace = true;
				continue;
			} else {
				return false;
			}
		}
		
		if (dateNumberCounter != 3 || dateSeparatorCounter != 2) {
			return false;
		}
		
		return true;
	}
	
	public static void printWelcomeMessage() {
		System.out.println("");
		System.out.println("This program prints out the day of the week for a given day (1..31), month (1..12) and year");	
	}
	
	private static void interactWithUser() {
		Scanner input = new Scanner(System.in);

		while (true) {		
			System.out.print("\nEnter a date with MM/DD/YYYY format (or q to exit): ");
			
			String userInput = input.nextLine();
			
			char[] userCharacters = userInput.toCharArray();
			
			int userDay = 0;
			int userMonth = 0;
			int userYear = 0;
			int userBuffer = 0;
			
			if (isExitCode(userCharacters)) {
				return;
			}
			
			if (!checkDateFormat(userCharacters)) {
				System.out.println(WRONG_DATE_FORMAT);
				continue;
			}	
			
			for (char userCharacter : userCharacters) {	
				if (userCharacter >= '0' && userCharacter <= '9') {
					userBuffer = userBuffer * 10 + ((int)userCharacter - (int)'0');
				} else {
					if (userMonth == 0) {
						userMonth = userBuffer;
					} else {
						userDay = userBuffer;
					} 
					
					userBuffer = 0;
				}
			}
						
			userYear = userBuffer;
			
			if (!checkDate(userDay, userMonth, userYear)) {
				System.out.println(WRONG_DATE);
				continue;
			}

			System.out.printf("\nDay of week %d/%d/%d: %s\n", userMonth, userDay,  userYear,
				getDayOfWeek(userDay, userMonth, userYear));	
		}
	}
	
	public static void main(String[] args) {	
		printWelcomeMessage();
		
		interactWithUser();
	}
}